-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Client Credentials Grant #1629
base: master
Are you sure you want to change the base?
Client Credentials Grant #1629
Conversation
@xtremerui I've been evaluating Dex as SP front ending Okta IdP. One of the use cases, I was looking at is support for client_credentials grant type. In a way, I want client application to use static client id and secret, configured at the time of Dex connector configuration, to retrieve id_token, refresh_token, access_token, code from Dex. This PR is going to support that? The connector type 'am exploring is OIDC. |
@karunchennuri yes we have similar use case thus we implemented this in our fork https://github.com/concourse/dex. Not sure how it is gonna be in upstream. |
@xtremerui I tested this PR on the master branch of dex. Worked perfectly fine. |
@karunchennuri glad it works. The test could be ran using the Lines 44 to 45 in 2ca992e
make test |
@xtremerui Would you be open to update this PR since it has conflicts? |
@mvdkleijn absolutely. Most of my PRs got conflicts I will update all of them. Thank you! |
d06e60b
to
37225ee
Compare
579a1de
to
133d9b6
Compare
47d4519
to
b648030
Compare
b648030
to
00c37b6
Compare
5b265dd
to
12421b2
Compare
12421b2
to
378e4c2
Compare
4530e4b
to
1eeff38
Compare
1eeff38
to
93b8d35
Compare
e84cf0e
to
dbb4f3e
Compare
@sagikazarmark could I get some feedback on this PR please? |
Since client_credentials can't be used with 2FA (U2F, WebAuthN, even OTP), I think its value is limited in real world scenarios. Modern orgs are at the point where they're literally hunting down and disabling APIs that only use username/password auth without a second factor. Dex's Access Tokens were never intended to have meaning outside of Dex itself. They're intended to be opaque to other services. The concerns about scopes and audience could be resolved by configuration. E.g. you could limit what scopes or audiences a specific client_id could be issued. If you need a flexible CA to issue credentials automation, you may want to look at HashiCorp Vault. Service-to-service credentials have different lifecycle and issuance requirements than human ones (e.g. you don't want a CI job to break when a user leaves the company). And you generally want to issue automation credentials based on the identity of the machine the automation is running on (e.g. a cloud VM identity[0][1] or kubernetes container identity[2]). That being said, I don't work on Dex anymore. The OAuth2 and OpenID Connect specs are routinely stretched in all sorts of interesting ways :) If you understand the draw backs but still feel that this is within Dex's scope, then please feel free to add support. [0] https://cloud.google.com/compute/docs/instances/verifying-instance-identity |
Why does dex even issue access tokens at all, if not to use them?
In practice, scopes are not super important in the client credentials sense. Effectively, the robot in question is demonstrating that it is a valid client with respect to dex by providing a valid client id and client secret.
I'm aware of the implementation - part of this PR is my work. :) Regarding being able to use any access token, this assumes that the token is still valid (not expired and not revoked). That's an interesting point though - probably want to restrict client credentials to require a client secret.... Regarding audience validation: "It is the responsibility is the resource server to determine whether the token should be used or not. A resource server may choose to ignore the audience claim and accept any valid token." For my purposes, that's a-ok.
I'm happy to work up a token verification endpoint for dex. :) I can even look at it next week.
Bigger picture is that we're integrating one or more external IdPs using dex on a per-cluster basis and wiring it all up to have Envoy talk to it. It'd be a bit of a pain to do what you're desribing. |
Yes, that would be a sane approach generally speaking. Unfortunately, in our case that'd be a bit messy.. we'd effectively be creating identies based on entire classes of containers. This seems like the appropriate use case for client credentials, no? As in, how is issuing a client id + client secret pair significantly different from issuing a username+password pair? |
fyi,I should point out that I'm not the original PR author. I'm just using the PR in my setup |
It should be used for accessing the
It might not be important in your use case, but APIs that use scopes for authorization would potentially be in a big trouble. Obviously, documentation can help, but it would be a funny thing to say "Hey, if you use scopes, client_credentials might make your API vulnerable if you issue tokens through Dex". Admittedly, configuration could be used to limit scopes.
Here is the deal though: if you accept any valid token, you accept ID tokens as well (because the way it's implemented in Dex). It's not that difficult to get an ID token for a user. Again, it might not be a problem for your use case, but it could mean a potential vulnerability in someone else's system.
I'm not 100% sure that's true for audiences. I mean, the audience is just hard-coded to the client ID.
Well, that's not my point at all. :)
I'm not entirely sure why: can Envoy only talk to one OAuth2 server at a time. Anyway, it's still all too coincidental to me: The fact that Dex uses OAuth2 under the hood for OIDC doesn't mean it's a fully fledged OAuth2 server. I'm afraid this is an incredibly deep rabbit hole: next thing we realize we are reviewing PRs for token introspection and revocation which are absolutely not in scope for Dex. And this PR basically makes an implementation detail (JWT access token) part of the "spec" without token introspection. I still haven't heard an argument why introducing a separate OAuth2 server for this purpose is impossible or a bad thing. |
If you've gotten the id token or access token, you're vulnerable. This is a given regardless, scopes or not. That's why access tokens are supposed to have a limited lifetime, no?
Would this concern not just be resolved by dealing with the audience correctly? Why is this not a problem for existing user credentials?
More specifically, in that this is Kubernetes we're talking about here, we're using Emissary-ingress, and no, it only allows a single AuthService to be configured. :)
I'm not clear why you wouldn't want to support token revocation? :) |
I'm not talking about stolen tokens. You can legitimately get your own ID token (eg. when using any kind of public client auth). And without audience check, a user could access any of the services that accepts a Dex issued JWT token (id or access).
What existing user credentials? :) Currently, the access token issued by Dex should only be consumed by Dex. So I guess technically you are right: Dex is vulnerable, although when it's the only audience apart from the client, this is probably less interesting.
Can you point me to some sort of documentation? I'd like to understand how they are consuming both OIDC and OAuth2 client credentials at the same time.
Technically, it's not. There is no token introspection implemented, so everything you rely on is implementation detail. That being said, I guess people would be mad if we changed it... Let's pretend for a moment that we want to expand Dex and make it a fully fledged OAuth2 server. I'm afraid there is still a whole lot of work we would have to do to make it secure enough and we have a whole lot of other things on our plates right now. I guess we could hide it behind feature flags, exempt it from the backwards compatibility promise.... I need to think about it a bit more. I wouldn't mind to here from @xtremerui as well: how they use it, in what environment, etc. |
Appreciate the input from you all! Here is how Concourse uses client credentials grant for its worker node. First, we use Dex as a third party library in Concousre. Typically, Concourse has two type of nodes: web and worker; and a CLI called fly. Dex server runs as the auth server in each web node. Web UI and fly CLI are user interfaces that accessing Concourse API. They use auth code flow mainly. Additionlly, as being a CLI, fly needs to support auth when no browser is available i.e. bot in CI. So we submitted #1621 and it works well for us. On the other hand, worker becomes our problem with Dex. Concourse worker is a containerized machine that running tasks that assigned from In summary, worker need to auth with Dex for access token for below ATC endpoints:
Since there is no user involved and it is a web node to worker node authentication, we think it falls perfectly into the scenario where client credentials grant should be used. |
6536373
to
a759248
Compare
a759248
to
f7a0f79
Compare
f7a0f79
to
7f90e61
Compare
fwiw, the use case that @xtremerui described is very congruent with my own internal use case as well. |
7f90e61
to
59bfbd3
Compare
a031678
to
73f1657
Compare
1905f8f
to
4e3fe5b
Compare
4e3fe5b
to
895f3b2
Compare
Hey folks, is there anything I can do to help this PR move forward? |
895f3b2
to
7a07880
Compare
Signed-off-by: Rui Yang <[email protected]>
This fixes two issues in the existing client credentials change: - client_credentials was not listed as a supported grant type - access tokens are not the storage ID Signed-off-by: Michael Kelly <[email protected]>
Signed-off-by: Rui Yang <[email protected]>
7a07880
to
3f0f531
Compare
Hi there, any intention still to merge this feature? |
I've tested the fork this change is based on and found that in the case of a public client, Dex will issue client credentials for the public client if I provide the client ID and leave out the secret value (or set it to null). This is an issue for our use; simply knowing the client ID (which is sent in plaintext by the UI when getting a token) is enough to get an access token. Not sure if that has been resolved in this PR though. We've ended up using the Device Code Flow with a staticClient and staticPassword as an alternative, but having full support for the Client Credentials Grant would be better. |
With the allowedGrants, I think now we can add the support for client credentials grant and make it not enabled by default. @sagikazarmark what do you think? |
Hello, Thank you very much for your work. Thanks in advance :-) |
so client can get access to Dex resources e.g. forwarding auth request and performing token exchange while handling callback from Dex.